/**
 * 
 */
package com.goldentrail.neo4j;

import java.util.ArrayList;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * Contains a path as returned by the Neo4j server
 * @author mikeagun
 * 
 */
public class PathResult {
	private ArrayList<Neo4jNode> nodes;
	private ArrayList<Relationship> rels;
	private Neo4jNode start;
	private Neo4jNode end;
	private int length;

	/**
	 * Default constructor. private because it should not be used outside of this class as there is no value in an unspecified path
	 */
	private PathResult() {

	}

	/**
	 * Fills in all the details of a path as returned by the server
	 * @param nodes  nodes on the path
	 * @param relationships  relationships between the nodes on the path
	 * @param start  start node of the path
	 * @param end  end node of the path
	 * @param length  length of the path
	 */
	public PathResult(ArrayList<Neo4jNode> nodes,
			ArrayList<Relationship> relationships, Neo4jNode start,
			Neo4jNode end, int length) {
		this.nodes = nodes;
		this.rels = relationships;
		this.start = start;
		this.end = end;
		this.length = length;
	}

	/**
	 * Gets the start node of the path
	 * @return start node of the path
	 */
	public Neo4jNode getStart() {
		return start;
	}

	/**
	 * Gets the end node of the path
	 * @return end node of the path
	 */
	public Neo4jNode getEnd() {
		return end;
	}

	/**
	 * Gets the list of nodes on the path, including start and end
	 * @return list of nodes on the path
	 */
	public ArrayList<Neo4jNode> getNodes() {
		return nodes;
	}

	/**
	 * Gets the list of relationships on the path
	 * @return list of relationships on the path
	 */
	public ArrayList<Relationship> getRelationships() {
		return rels;
	}
	
	/**
	 * Gets the length of the path
	 * @return length of the path
	 */
	public int getLength() {
		return length;
	}

	
	/**
	 * Creates a PathResult from a JSONObject representing the path as returned by the server 
	 * @param json  JSONObject representing the path
	 * @return PathResult as specified by JSON
	 */
	public static PathResult fromJson(JSONObject json) {
		PathResult result = new PathResult();
		try {
			ArrayList<Neo4jNode> nodes = new ArrayList<Neo4jNode>();
			ArrayList<Relationship> rels = new ArrayList<Relationship>();
			result.start = new Neo4jNode(json.getString("start"));
			result.end = new Neo4jNode(json.getString("end"));
			result.length = json.getInt("length");
			JSONArray nodeArray = json.getJSONArray("nodes");
			JSONArray relArray = json.getJSONArray("relationships");
			for (int i = 0; i < nodeArray.length(); i++) {
				nodes.add(new Neo4jNode(nodeArray.getString(i)));
			}
			for (int i = 0; i < relArray.length(); i++) {
				rels.add(new Relationship(relArray.getString(i)));
			}
			result.nodes = nodes;
			result.rels = rels;

		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return result;
	}

	
	/**
	 * Gets the JSONObject that represents this path
	 * @return JSONObject representing this path
	 */
	public JSONObject getJson() {
		JSONObject json = new JSONObject();
		try {
			if (getStart() != null)
				json.put("start", getStart().getURI());
			if (getEnd() != null)
				json.put("end", getEnd().getURI());
			json.put("length", getLength());
			for (Neo4jNode neoNode : getNodes())
				json.accumulate("nodes", neoNode.getURI());
			for (Relationship rel : getRelationships())
				json.accumulate("relationships", rel.getURI());
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return json;
	}

	
	/** 
	 * Gets the string representation of this path with no whitespace added
	 * @return
	 */
	public String getJsonString() {
		return getJson().toString();
	}

	
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		try {
			return getJson().toString(2);
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	/** 
	 * Gets the pretty print string representation of this path
	 * @param indentFactor  how far to indent each level
	 * @return pretty print string with whitespace added
	 */
	public String toString(int indentFactor) {
		try {
			return getJson().toString(indentFactor);
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
}
